module Explode.StageSelector;
private import Explode.Stage;
private import Explode.Player;
private import Explode.GameConfig;
private import Explode.GameState;
private import Form.MenuItem;
private import State.IState;
private import Input.KeyCode;
private import Input.GamePad;
private import Graphics.IGraphics;
private import System.Console;
private import std.file;
private import std.string;
private import std.format;

/**
*	エディットのステージ選択用
*/
public class StageSelectState : BasicState {
	public const int SELECT      = 1;
	public const int CANCEL      = 0;
	protected int _returnValue = 0;
	public int returnValue(){return _returnValue;}
	protected string _fileName = "";
	public string fileName(){return _fileName;}

	protected const int WIDTH = 320 , HEIGHT = 400;
	protected string _title = "SELECT STAGE";
	protected int _bestTime = -1;

	private class Background : IDrawingEntry{
		public float x(){return 0;}
		public float y(){return 0;}
		public float z(){return 200;}
		public bool drawingEntry( IGraphics g ){
			return g.addDrawingEntry( this );
			
		} //
		public bool draw( IGraphics g ){
			g.setViewport( 0 , 0, WIDTH , HEIGHT );
			g.drawFilledRect( 0 , 0 , WIDTH , HEIGHT , Color.create(0x33000000u) );
			string txt  = _title;
			string btxt = format("BEST TIME %06d" , _bestTime );
			int ww = 32 , hh = 64;
				g.drawText( txt , ( WIDTH - ww * txt.length  ) / 2 , 70 , Color.create( 0x66ffffffu ) , ww , hh );
				g.drawText( txt , ( WIDTH - ww * txt.length  ) / 2 , 50 , Color.create( 0xccff0000u ) , ww , hh );
			_pstage.draw( g );
			ww = 8; hh = 16;
			if ( _bestTime > 0 )
				g.drawText( btxt 
						, ( WIDTH - ww * btxt.length ) / 2 
						, (HEIGHT - hh) / 2 
						, Color.create( 0xff888800u ) , ww , hh );

			g.drawFilledRect( 64 , HEIGHT / 2 + 80 , WIDTH - 128 ,  26 * 3 , Color.create( 0x330000ffu ) , 0 );
			return true;
		} //
	} //


	private IState _caller;

	private int _frameCnt;
	protected IGamePad _gamepad;
	protected IMenuItem[] _items; 
	protected MenuItem _cancelMenu;
	protected EnumMenuItem _stageMenu;
	
	protected IMenuItem _activeItem ;
	protected IState _nextState ;
	protected IGraphics _graphics;

	protected string[] _stageValues;
	private  Background _background;
	protected PreviewStage _pstage;
	
	protected string _baseDir ;
	
	public string title() {
		return _title;
	} //
	public void title( string v ) {
		_title = v;
	} //


	public this( string baseDir , IGamePad pad , IGraphics g ){
		_baseDir   = baseDir;
		_gamepad   = pad;
		_graphics  = g;
	} //

	public IState call( IState caller ) {
		_caller = caller;
		_nextState = this;
		_gamepad.reset();
		_returnValue = 0;
		initMenu();
		_frameCnt = 0;
		return this;
	} //
	
	protected void initMenu() {
		if ( _cancelMenu is null ) {
			Console.write("Create SelectMenu...");
			_background = new Background();
			_pstage		= new PreviewStage( _graphics );
			_stageMenu   = new EnumMenuItem("FILE SELECT    ");
			_cancelMenu  = new MenuItem("CANCEL");
			
			_items~=_stageMenu;
			_items~=_cancelMenu;

			MenuItemConnector.connectVertical( _items );
			_activeItem = _stageMenu.activate();
			
			int xx = WIDTH / 2 , yy = HEIGHT / 2 + 60;
			_stageMenu.moveTo(   xx , yy +=  30 );
			_cancelMenu.moveTo(  xx , yy +=  30 );
			_stageMenu.setSelectHandler(  &onStageMenuSelect );
			_stageMenu.setChangedHandler(  &onStageMenuChange );
			_cancelMenu.setSelectHandler( &onCancelMenuSelect );

			setSelectValues( );
			setStageNumber( 1 );
			Console.writeln("OK");
		} else {
			if ( _activeItem is _cancelMenu ) _activeItem = _activeItem.up;
			reloadStage();
		}
	} //
	
	protected void setSelectValues( int index = 0) {
		for ( int i = 1 ; i <= GameConfig.editStageLength ; i++ ) {
			_stageValues ~= std.string.toString(i);
		}
		_stageMenu.setValues( "FILE   " , _stageValues , index );
	} //

	int _cntY = 0, _cntX = 0;
	public IState action() {
		_frameCnt ++;
		foreach ( int i , IMenuItem item ; _items  ) {
			item.action();
		} //
		if ( _frameCnt > 30 ) {
			if ( _gamepad.y != 0 )  _cntY++; 
			else					_cntY = 0;
			if ( _gamepad.x != 0 )  _cntX++;
			else					_cntX = 0;
			if ( _cntY % 10 == 1 ) {
				_activeItem = ( _gamepad.y > 0 ) ? _activeItem.down  : _activeItem.up;
			}
			if ( _cntX % 10 == 1  || ( _cntX > 60 && _cntX % 3 == 1 ) ) {
				_activeItem = ( _gamepad.x > 0 ) ? _activeItem.right : _activeItem.left;
			}
		}
		if ( _activeItem is _stageMenu ) {
				 _pstage.action();
			if ( _pstage.frameCnt < 10 ) _pstage.zoomOut();
		}

		if ( _gamepad.getButton( 0 ) != 0 ) {
			_activeItem.select();
		}

		return _nextState;
	} //

	public IState draw( IGraphics g ) {
		foreach ( int i , IMenuItem item ; _items  ) {
			item.drawingEntry( g );
		} //
		_background.drawingEntry( g );
		g.draw();
		return this;
	} //

	int _lastnum = 1;
	public int setStageNumber( int num ) {
		string file   = format("edit%04d.txt" , num );
		string src	  = _baseDir ~ "/" ~ file;
		string replay = _baseDir ~ "/replay/" ~ file;
		string defSrc = _baseDir ~ "/edit0001.txt";
		
		if ( !exists( src ) ) {
			Console.writeln("file not found %s" , src);
			src = defSrc;
			num = 1;
			if( !exists( src ) ) {
				return false;
			}
		}
		
		if (_pstage.loadStageFromFile( src ) ) {
			_fileName = src;
		}

		for ( int i = 0 ; i < 30 ; i++ ) _pstage.zoomOut();
		if ( exists( replay ) ) {
			string  head = split( cast(string)read( replay ) , "[body]" )[0];
			string[] dat = split( head , ",");
			_bestTime = cast(int)atoi( dat[0] );
		} else {
			_bestTime = -1;
		}
		_lastnum = num;
		return num;
	} //
	
	public void reloadStage(){
		setStageNumber( _lastnum );
	} //

	public bool onKeyDown( int keyCode ){
		switch ( keyCode ) {
			case KeyCode.UP:
				_gamepad.y = -1;
				break;
			case KeyCode.DOWN:
				_gamepad.y =  1;
				break;
			case KeyCode.LEFT:
				_gamepad.x = -1;
				break;
			case KeyCode.RIGHT:
				_gamepad.x =  1;
				break;
			case KeyCode.Z:
			case KeyCode.ENTER:
				_gamepad.setButton( 0 , 1 );
				break;
			case KeyCode.X:
				_gamepad.setButton( 1 , 1 );
				break;
			default:
				break;
		}
		return true;
	} //
	public bool onKeyUp( int keyCode ){
		switch ( keyCode ) {
			case KeyCode.UP:
				_gamepad.y = 0;
				break;
			case KeyCode.DOWN:
				_gamepad.y = 0;
				break;
			case KeyCode.LEFT:
				_gamepad.x = 0;
				break;
			case KeyCode.RIGHT:
				_gamepad.x = 0;
				break;
			case KeyCode.Z:
			case KeyCode.ENTER:
				_gamepad.setButton( 0 , 0 );
				break;
			case KeyCode.X:
				_gamepad.setButton( 1 , 0 );
				break;
			case KeyCode.SPACE:
				_returnValue = CANCEL;
				_nextState = _caller.call( this );
				break;
			default:
				break;
		}
		return true;
	} //
	public bool onJoyAxis( int deviceId , int axis , int delta ){
		if ( axis == JOYAXIS_X ) {
			if( delta != 0 ) _gamepad.x = ( delta > 0 ) ? 1 : -1;
			else			 _gamepad.x = 0;
		}
		if ( axis == JOYAXIS_Y ){
			if( delta != 0 ) _gamepad.y = ( delta > 0 ) ? 1 : -1;
			else			 _gamepad.y = 0;
		}
		return true;
	} //
	
	public bool onJoyButtonDown( int id , int button ) {
		int bm = GameConfig.getButtonMap( button );
		if ( bm == 9 ) { 
			_returnValue = CANCEL;
			_nextState = _caller.call( this );
		}
		else
		_gamepad.setButton( GameConfig.getButtonMap( button ) , 1 );
		return true;
	} //

	public bool onJoyButtonUp( int id , int button ) {
		_gamepad.setButton( GameConfig.getButtonMap( button ) , 0 );
		return true;
	} //


	public void onCancelMenuSelect( IMenuItem im ) {
		_returnValue = CANCEL;
		_nextState = _caller.call( this );
		_fileName = "";
		Console.writeln("CANCEL");
	} //

	public void onStageMenuSelect( IMenuItem im ) {
		_returnValue = SELECT;
//		_selectedValue = atoi( _stageMenu.value );
		_nextState = _caller.call( this );
		Console.writeln("RETURN TO  GAME!");
	} //

	public void onStageMenuChange( EnumMenuItem im , string selectedValue , int selectedIndex ) {
		int num = cast(int)atoi( selectedValue );
		setStageNumber( num );
	} //

} //



